package com.yt.order.websocket;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.yt.order.models.bo.BillSaveBO;
import com.yt.order.models.dto.BillDTO;
import org.springframework.stereotype.Component;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * WebSocket通话处理类
 * 处理拨号、接听、挂断等事件
 */
@ServerEndpoint("/websocket/call/{phone}")
@Component
@Controller
public class CallWebSocket {
    
    // 存储连接的会话，key为手机号
    private static Map<String, Session> phoneSessionMap = new ConcurrentHashMap<>();

    // 存储通话账单ID，key为虚拟号
    private static Map<String, Long> callBillIdMap = new ConcurrentHashMap<>();
    
    // 注入BillService
    private static com.yt.order.models.service.IBillService billService;
    
    // 使用Dubbo注解注入VirtualNumberService
    private static com.yt.user.models.service.IVirtualNumberService virtualNumberService;
    
    // 使用Dubbo注解注入AccountInfoService
    private static com.yt.user.models.service.IAccountInfoService accountInfoService;
    
    @Autowired
    public void setBillService(com.yt.order.models.service.IBillService billService) {
        CallWebSocket.billService = billService;
    }
    
    @org.apache.dubbo.config.annotation.DubboReference
    public void setVirtualNumberService(com.yt.user.models.service.IVirtualNumberService virtualNumberService) {
        CallWebSocket.virtualNumberService = virtualNumberService;
    }
    
    @org.apache.dubbo.config.annotation.DubboReference
    public void setAccountInfoService(com.yt.user.models.service.IAccountInfoService accountInfoService) {
        CallWebSocket.accountInfoService = accountInfoService;
    }
    
    // 当前连接的手机号
    private String phone;
    
    /**
     * 连接建立时调用
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("phone") String phone) {
        this.phone = phone;
        phoneSessionMap.put(phone, session);
        System.out.println("手机号 " + phone + " 已连接，当前在线数: " + phoneSessionMap.size());
    }
    
    /**
     * 连接关闭时调用
     */
    @OnClose
    public void onClose() {
        phoneSessionMap.remove(phone);
        System.out.println("手机号 " + phone + " 已断开，当前在线数: " + phoneSessionMap.size());
    }
    
    /**
     * 收到客户端消息时调用
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("收到来自 " + phone + " 的消息: " + message);
        
        try {
            JSONObject jsonMessage = JSON.parseObject(message);
            String type = jsonMessage.getString("type");
            
            if ("call".equals(type)) {
                // 处理呼叫消息，创建账单
                handleCallMessage(jsonMessage);
            } else if ("hangup".equals(type)) {
                // 处理挂断消息，更新账单
                handleHangupMessage(jsonMessage);
            } else if ("answer".equals(type)) {
                // 处理接听消息的逻辑
                handleAnswerMessage(jsonMessage);
            }
        } catch (Exception e) {
            System.err.println("处理消息时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 处理呼叫消息
     */
    private void handleCallMessage(JSONObject jsonMessage) {
        try {
            String from = jsonMessage.getString("from");
            String to = jsonMessage.getString("to");
            String virtualNumber = jsonMessage.getString("virtualNumber");
            Long time = jsonMessage.getLong("time");
            
            // 检查账户状态
            if (!checkAccountStatus(from)) {
                // 账户状态异常，拒绝呼叫
                System.out.println("账户状态异常，拒绝呼叫: from=" + from);
                // 发送拒绝呼叫的消息给客户端
                sendRejectMessage(from, "账户余额不足或处于欠费状态，无法发起呼叫");
                return;
            }
            
            // 创建账单
            BillSaveBO billSaveBO = new BillSaveBO();
            billSaveBO.setCallerPhone(from);
            billSaveBO.setCalleePhone(to);
            billSaveBO.setVirtualNumber(virtualNumber);
            
            // 调用服务创建账单
            BillDTO billDTO = new BillDTO();
            billDTO.setCallerPhone(from);
            billDTO.setCalleePhone(to);
            billDTO.setVirtualNumber(virtualNumber);
            billDTO.setCreateTime(new Date(time));
            
            // 插入账单记录
            boolean result = billService.insertAllColumn(billDTO);
            
            if (result && billDTO.getId() != null) {
                // 保存账单ID，用于后续更新
                callBillIdMap.put(virtualNumber, billDTO.getId());
                System.out.println("已创建账单: ID=" + billDTO.getId() + ", from=" + from + ", to=" + to + ", virtualNumber=" + virtualNumber);
            } else {
                System.err.println("创建账单失败: from=" + from + ", to=" + to + ", virtualNumber=" + virtualNumber);
            }
            
            // 转发呼叫请求给目标号码
            String toPhone = jsonMessage.getString("to");
            System.out.println("准备向被叫方 " + toPhone + " 转发呼叫请求");
            try {
                sendMessageTo(toPhone, jsonMessage.toJSONString());
                System.out.println("已向被叫方 " + toPhone + " 转发呼叫请求");
            } catch (Exception e) {
                System.err.println("向被叫方 " + toPhone + " 转发呼叫请求失败: " + e.getMessage());
                // 向主叫方发送错误信息
                JSONObject errorMessage = new JSONObject();
                errorMessage.put("type", "error");
                errorMessage.put("message", "被叫方暂时无法接通");
                errorMessage.put("time", System.currentTimeMillis());
                sendMessageTo(from, errorMessage.toJSONString());
            }
        } catch (Exception e) {
            System.err.println("处理呼叫消息时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 处理挂断消息
     */
    private void handleHangupMessage(JSONObject jsonMessage) {
        try {
            String from = jsonMessage.getString("from");
            String to = jsonMessage.getString("to");
            String virtualNumber = jsonMessage.getString("virtualNumber");
            Long hangupTime = jsonMessage.getLong("time");
            
            // 根据虚拟号获取账单ID
            Long billId = null;
            BillDTO billDTO = null;
            
            // 如果virtualNumber为空，则尝试通过from和to查找账单
            if (virtualNumber == null || virtualNumber.isEmpty()) {
                System.out.println("virtualNumber为空，尝试通过from和to查找账单: from=" + from + ", to=" + to);
                // 根据from和to查找账单（考虑两种方向）
                com.baomidou.mybatisplus.mapper.EntityWrapper<BillDTO> wrapper = 
                    new com.baomidou.mybatisplus.mapper.EntityWrapper<>();
                // 条件1: from是主叫，to是被叫
                wrapper.eq("caller_phone", from).eq("callee_phone", to);
                // 或条件2: to是主叫，from是被叫（反向通话）
                wrapper.or().eq("caller_phone", to).eq("callee_phone", from);
                wrapper.isNull("call_duration"); // 查找尚未设置通话时长的账单（未完成的通话）
                List<BillDTO> bills = billService.selectList(wrapper);
                if (!bills.isEmpty()) {
                    // 选择最新的未完成账单
                    billDTO = bills.get(0);
                    for (BillDTO b : bills) {
                        if (b.getCreateTime().after(billDTO.getCreateTime())) {
                            billDTO = b;
                        }
                    }
                    billId = billDTO.getId();
                    virtualNumber = billDTO.getVirtualNumber();
                    System.out.println("通过from和to找到账单: ID=" + billId + ", virtualNumber=" + virtualNumber);
                }
            } else {
                // 原有逻辑：根据虚拟号获取账单ID
                billId = callBillIdMap.get(virtualNumber);
                if (billId != null) {
                    // 根据ID查找账单
                    billDTO = billService.selectById(billId);
                }
            }
            
            if (billDTO != null) {
                // 检查是否已接听（通过是否存在接听时间字段）
                // 如果没有接听时间，说明未接听，不计费
                if (billDTO.getAnswerTime() == null) {
                    System.out.println("通话未被接听，不计费");
                } else {
                    // 计算通话时长（秒）
                    if (billDTO.getAnswerTime() != null) {
                        // 从接听时间开始计算通话时长
                        long duration = (hangupTime - billDTO.getAnswerTime().getTime()) / 1000;
                        billDTO.setCallDuration((int) duration);
                        
                        // 计算费用
                        calculateCallFee(billDTO, virtualNumber, duration);
                        
                        // 扣费
                        deductFeeFromAccount(billDTO, billDTO.getCallerPhone());
                    }
                }
                
                // 设置更新时间
                billDTO.setUpdateTime(new Date(hangupTime));
                
                // 更新账单
                boolean result = billService.updateById(billDTO);
                
                if (result) {
                    // 移除账单ID记录
                    if (virtualNumber != null && !virtualNumber.isEmpty()) {
                        callBillIdMap.remove(virtualNumber);
                    }
                    System.out.println("已更新账单: ID=" + billDTO.getId() + ", virtualNumber=" + virtualNumber + ", duration=" + billDTO.getCallDuration() + "秒, totalFee=" + billDTO.getTotalFee() + "分, virtualFee=" + billDTO.getVirtualFee() + "分");
                } else {
                    System.err.println("更新账单失败: ID=" + billDTO.getId());
                }
            } else {
                System.err.println("未找到对应的账单记录: virtualNumber=" + virtualNumber + ", from=" + from + ", to=" + to);
            }
            
            // 转发挂断消息给通话双方
            sendMessageTo(from, jsonMessage.toJSONString());
            sendMessageTo(to, jsonMessage.toJSONString());
        } catch (Exception e) {
            System.err.println("处理挂断消息时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 处理接听消息
     */
    private void handleAnswerMessage(JSONObject jsonMessage) {
        try {
            String from = jsonMessage.getString("from");
            String to = jsonMessage.getString("to");
            String virtualNumber = jsonMessage.getString("virtualNumber");
            Long answerTime = jsonMessage.getLong("time");
            
            // 根据虚拟号获取账单ID
            Long billId = callBillIdMap.get(virtualNumber);
            BillDTO billDTO = null;
            
            if (billId != null) {
                // 根据ID查找账单
                billDTO = billService.selectById(billId);
                
                if (billDTO != null) {
                    // 设置接听时间
                    billDTO.setAnswerTime(new Date(answerTime));
                    
                    // 更新账单
                    boolean result = billService.updateById(billDTO);
                    if (result) {
                        System.out.println("已更新账单接听时间: ID=" + billDTO.getId() + ", virtualNumber=" + virtualNumber + ", answerTime=" + answerTime);
                    } else {
                        System.err.println("更新账单接听时间失败: ID=" + billDTO.getId());
                    }
                }
            } else {
                System.err.println("未找到对应的账单记录: virtualNumber=" + virtualNumber);
            }
            
            // 转发应答给目标号码
            String toPhone = jsonMessage.getString("to");
            sendMessageTo(toPhone, jsonMessage.toJSONString());
        } catch (Exception e) {
            System.err.println("处理接听消息时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 检查账户状态
     * @param callerPhone 主叫号码
     * @return 账户状态是否正常
     */
    private boolean checkAccountStatus(String callerPhone) {
        try {
            // 根据手机号查询账户信息
            com.baomidou.mybatisplus.mapper.EntityWrapper<com.yt.user.models.dto.AccountInfoDTO> wrapper = 
                new com.baomidou.mybatisplus.mapper.EntityWrapper<>();
            wrapper.eq("phone", callerPhone);
            com.yt.user.models.dto.AccountInfoDTO accountInfo = accountInfoService.selectOne(wrapper);
            
            if (accountInfo != null) {
                // 检查是否欠费
                if (accountInfo.getIsArrears() != null && accountInfo.getIsArrears() == 1) {
                    System.out.println("账户欠费，无法发起呼叫: callerPhone=" + callerPhone);
                    return false;
                }
                
                // 检查余额是否大于0
                if (accountInfo.getPreDeposit() == null || accountInfo.getPreDeposit() <= 0) {
                    System.out.println("账户余额为0，无法发起呼叫: callerPhone=" + callerPhone);
                    return false;
                }
                
                return true;
            } else {
                System.err.println("未找到账户信息: callerPhone=" + callerPhone);
                return false;
            }
        } catch (Exception e) {
            System.err.println("检查账户状态时发生错误: " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }
    
    /**
     * 发送拒绝呼叫消息
     * @param callerPhone 主叫号码
     * @param reason 拒绝原因
     */
    private void sendRejectMessage(String callerPhone, String reason) {
        try {
            JSONObject rejectMessage = new JSONObject();
            rejectMessage.put("type", "reject");
            rejectMessage.put("reason", reason);
            rejectMessage.put("time", System.currentTimeMillis());
            
            sendMessageTo(callerPhone, rejectMessage.toJSONString());
        } catch (Exception e) {
            System.err.println("发送拒绝消息时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 计算通话费用
     * @param billDTO 账单对象
     * @param virtualNumber 虚拟号
     * @param duration 通话时长（秒）
     */
    private void calculateCallFee(BillDTO billDTO, String virtualNumber, long duration) {
        try {
            // 查询虚拟号信息获取费率
            // 使用EntityWrapper根据virtualNumber字段查询，而不是使用ID查询
            com.baomidou.mybatisplus.mapper.EntityWrapper<com.yt.user.models.dto.VirtualNumberDTO> wrapper = 
                new com.baomidou.mybatisplus.mapper.EntityWrapper<>();
            wrapper.eq("virtual_number", virtualNumber);
            com.yt.user.models.dto.VirtualNumberDTO virtualNumberDTO = 
                virtualNumberService.selectOne(wrapper);
            
            if (virtualNumberDTO != null && virtualNumberDTO.getRate() != null) {
                // 获取费率（分/分钟）
                long rate = virtualNumberDTO.getRate();
                
                // 计算虚拟号服务费用（分）
                // 时长（秒）转为分钟并计算费用
                long virtualFee = (long) Math.ceil((double) duration / 60) * rate;
                
                // 这里可以添加其他费用计算逻辑
                // 暂时将总费用设为虚拟号服务费用
                int totalFee = (int) virtualFee;
                
                // 设置费用
                billDTO.setVirtualFee(virtualFee);
                billDTO.setTotalFee(totalFee);
            } else {
                System.err.println("未找到虚拟号或费率信息: virtualNumber=" + virtualNumber);
            }
        } catch (Exception e) {
            System.err.println("计算费用时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 从账户中扣费
     * @param billDTO 账单对象
     * @param callerPhone 主叫号码
     */
    private void deductFeeFromAccount(BillDTO billDTO, String callerPhone) {
        try {
            System.out.println("开始处理扣费逻辑，主叫号码: " + callerPhone + ", 账单ID: " + billDTO.getId() + ", 费用: " + billDTO.getTotalFee() + "分");
            
            if (billDTO.getTotalFee() == null || billDTO.getTotalFee() <= 0) {
                System.out.println("费用为0或为空，无需扣费: callerPhone=" + callerPhone);
                return;
            }
            
            // 根据手机号查询账户信息
            com.baomidou.mybatisplus.mapper.EntityWrapper<com.yt.user.models.dto.AccountInfoDTO> wrapper = 
                new com.baomidou.mybatisplus.mapper.EntityWrapper<>();
            wrapper.eq("phone", callerPhone);
            com.yt.user.models.dto.AccountInfoDTO accountInfo = accountInfoService.selectOne(wrapper);
            
            if (accountInfo != null) {
                System.out.println("找到主叫方账户信息: accountId=" + accountInfo.getId() + ", 当前余额=" + accountInfo.getPreDeposit() + "分");
                
                // 检查余额是否足够
                if (accountInfo.getPreDeposit() != null && accountInfo.getPreDeposit() >= billDTO.getTotalFee()) {
                    // 余额充足，正常扣费
                    long newPreDeposit = accountInfo.getPreDeposit() - billDTO.getTotalFee();
                    accountInfo.setPreDeposit(newPreDeposit);
                    
                    // 更新累计消费
                    if (accountInfo.getTotalConsumption() == null) {
                        accountInfo.setTotalConsumption((long) billDTO.getTotalFee());
                    } else {
                        accountInfo.setTotalConsumption(accountInfo.getTotalConsumption() + billDTO.getTotalFee());
                    }
                    
                    // 更新当月消费
                    if (accountInfo.getMonthConsumption() == null) {
                        accountInfo.setMonthConsumption((long) billDTO.getTotalFee());
                    } else {
                        accountInfo.setMonthConsumption(accountInfo.getMonthConsumption() + billDTO.getTotalFee());
                    }
                    
                    // 更新账户信息
                    boolean result = accountInfoService.updateById(accountInfo);
                    if (result) {
                        System.out.println("扣费成功: accountId=" + accountInfo.getId() + ", amount=" + billDTO.getTotalFee() + "分, balance=" + newPreDeposit + "分");
                    } else {
                        System.err.println("扣费失败: accountId=" + accountInfo.getId());
                    }
                } else {
                    // 余额不足，部分扣费并记录欠费
                    long arrearsAmount = billDTO.getTotalFee(); // 默认欠费全部金额
                    if (accountInfo.getPreDeposit() != null) {
                        // 先扣除剩余余额
                        arrearsAmount = billDTO.getTotalFee() - accountInfo.getPreDeposit();
                        System.out.println("余额不足，先扣除剩余余额: " + accountInfo.getPreDeposit() + "分，欠费金额: " + arrearsAmount + "分");
                        accountInfo.setPreDeposit(0L); // 余额清零
                    }
                    
                    // 更新累计消费
                    if (accountInfo.getTotalConsumption() == null) {
                        accountInfo.setTotalConsumption((long) billDTO.getTotalFee());
                    } else {
                        accountInfo.setTotalConsumption(accountInfo.getTotalConsumption() + billDTO.getTotalFee());
                    }
                    
                    // 更新当月消费
                    if (accountInfo.getMonthConsumption() == null) {
                        accountInfo.setMonthConsumption((long) billDTO.getTotalFee());
                    } else {
                        accountInfo.setMonthConsumption(accountInfo.getMonthConsumption() + billDTO.getTotalFee());
                    }
                    
                    // 设置账户为欠费状态
                    accountInfo.setIsArrears(1); // 1表示欠费
                    
                    // 更新欠费金额
                    if (accountInfo.getArrearsAmount() == null) {
                        accountInfo.setArrearsAmount(arrearsAmount);
                    } else {
                        accountInfo.setArrearsAmount(accountInfo.getArrearsAmount() + arrearsAmount);
                    }
                    
                    System.out.println("账户余额不足，已扣除剩余余额，当前欠费: " + arrearsAmount + "分");
                    
                    // 更新账户信息
                    boolean result = accountInfoService.updateById(accountInfo);
                    if (result) {
                        System.out.println("扣费处理完成: accountId=" + accountInfo.getId() + ", 欠费=" + arrearsAmount + "分");
                    } else {
                        System.err.println("扣费处理失败: accountId=" + accountInfo.getId());
                    }
                }
            } else {
                System.err.println("未找到账户信息: callerPhone=" + callerPhone);
            }
        } catch (Exception e) {
            System.err.println("扣费时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
        System.err.println("WebSocket发生错误: " + error.getMessage());
        error.printStackTrace();
        
        // 如果是连接中断异常，则执行清理操作
        if (phone != null) {
            phoneSessionMap.remove(phone);
            System.out.println("已清理手机号 " + phone + " 的会话信息");
        }
    }
    
    /**
     * 发送消息给指定手机号
     */
    public static void sendMessageTo(String phone, String message) throws IOException {
        Session session = phoneSessionMap.get(phone);
        if (session != null && session.isOpen()) {
            try {
                session.getBasicRemote().sendText(message);
            } catch (IOException e) {
                System.err.println("向手机号 " + phone + " 发送消息失败: " + e.getMessage());
                // 从会话映射中移除已断开的连接
                phoneSessionMap.remove(phone);
                throw e;
            }
        } else if (session != null) {
            System.err.println("向手机号 " + phone + " 发送消息失败: 会话已关闭");
            // 从会话映射中移除已断开的连接
            phoneSessionMap.remove(phone);
        } else {
            System.err.println("向手机号 " + phone + " 发送消息失败: 手机号未连接");
        }
    }
}